package com.github.xzb617.adm.service.impl;

import com.github.xzb617.adm.dao.FlowMetricMapper;
import com.github.xzb617.adm.service.RouteFlowMetricService;
import com.github.xzb617.domain.common.TextCondition;
import com.github.xzb617.domain.entity.FlowMetric;
import com.github.xzb617.domain.vo.LineChartVO;
import com.github.xzb617.domain.vo.echarts.*;
import com.github.xzb617.utils.DateFormatUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class RouteFlowMetricServiceImpl implements RouteFlowMetricService {

    private final FlowMetricMapper flowMetricMapper;

    public RouteFlowMetricServiceImpl(FlowMetricMapper flowMetricMapper) {
        this.flowMetricMapper = flowMetricMapper;
    }

    @Override
    public List<LineChartVO> getClientRouteMetrics(TextCondition condition) {
        // 查询 8 分钟之内的上报数据
        List<FlowMetric> metricsInLastTenMinute = this.flowMetricMapper.selectByStartTime(8, condition.getSearchText());

        // 根据AppId分组
        Map<String, List<FlowMetric>> collect = metricsInLastTenMinute.stream()
                .collect(Collectors.groupingBy(FlowMetric::getAppId));

        // 解析 过滤 转换
        List<LineChartVO> lineChartVOS = new ArrayList<>(collect.keySet().size());
        Set<Map.Entry<String, List<FlowMetric>>> entries = collect.entrySet();
        for (Map.Entry<String, List<FlowMetric>> entry : entries) {
            lineChartVOS.add(this.metricToChart(entry.getValue(), entry.getKey()));
        }

        return lineChartVOS;
    }

    /**
     * 构建图表数据模型
     * @param metrics 流控指标
     * @param appId 服务名称
     * @return
     */
    private LineChartVO metricToChart(List<FlowMetric> metrics, String appId) {
        // 获取 Legend 数组
        Map<String, List<FlowMetric>> instanceMap
                = metrics.stream().collect(Collectors.groupingBy(FlowMetric::getInstanceId));

        Set<String> legends = instanceMap.keySet();

        LineChartVO chart = new LineChartVO();
        chart.setTitle(new Title(appId, new Title.TextStyle()));
        chart.setTooltip(new Tooltip());
        chart.setLegend(new Legend(legends));
        chart.setColor(new String[]{"red", "green"});
        chart.setxAxis(new XAxis(resolveXAxisData(metrics)));
        chart.setyAxis(new YAxis());
        chart.setSeries(resolveSeries(metrics, legends));
        return chart;
    }

    private List<String> resolveXAxisData(List<FlowMetric> metrics) {
        Map<String, List<FlowMetric>> collect = metrics.stream().collect(Collectors.groupingBy(FlowMetric::getInstanceId));
        List<String> arr = new ArrayList<>();
        if (collect.size() > 0) {
            List<FlowMetric> value = collect.entrySet().stream().findFirst().get().getValue();
            arr = value.stream()
                    .sorted(Comparator.comparing(FlowMetric::getStartTime))
                    .filter(e -> e.getStartTime()!=null)
                    .map(e -> {
                        return DateFormatUtil.formatToHourAndMinute(e.getStartTime());
                    })
                    .distinct()
                    .collect(Collectors.toList());
        }
        return arr;
    }

    private List<Series> resolveSeries(List<FlowMetric> metrics, Set<String> legends) {
        Map<String, List<FlowMetric>> instanceFlowMetricMap = metrics.stream()
                .collect(Collectors.groupingBy(FlowMetric::getInstanceId));
        List<Series> seriesList = new LinkedList<>();
        for (String legend : legends) {
            Series series = new Series(legend, "line");
            List<FlowMetric> var = instanceFlowMetricMap.get(legend);
            List<FlowMetric> collect = var.stream().sorted(Comparator.comparing(FlowMetric::getStartTime))
                    .filter(e -> e.getStartTime() != null).collect(Collectors.toList());
            List<Long> seriesData = new LinkedList<>();
            for (FlowMetric flowMetric : collect) {
                seriesData.add(flowMetric.getTotalCount());
            }
            series.setData(seriesData);
            seriesList.add(series);
        }
        return seriesList;
    }
}
